Expose managed approval requirement on permission requests - #2080
Expose managed approval requirement on permission requests#2080joshspicer wants to merge 14 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Exposes managed approval requirements to TypeScript permission handlers.
Changes:
- Adds optional
managedApprovalRequiredmetadata. - Adds package-root type coverage.
Show a summary per file
| File | Description |
|---|---|
nodejs/src/types.ts |
Overlays managed approval metadata onto permission requests. |
nodejs/test/session-event-types.test.ts |
Verifies the field is publicly importable. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 3
- Review effort level: Medium
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 18f1bbc1-6001-43e2-b293-724505087f6a
13c3d37 to
03184d2
Compare
There was a problem hiding this comment.
Review details
Comments suppressed due to low confidence (1)
nodejs/src/types.ts:1108
- This overlay only updates the standalone type and
PermissionHandler; the publicSessionEvent/PermissionRequestedDatatypes still come from the generated schema, wherepermissionRequestlacks this property. Consequently, an event-only host (the documented path whenonPermissionRequestis omitted) cannot compileevent.data.permissionRequest.managedApprovalRequiredeven though the runtime sends it. Please overlay thepermission.requestedevent payload as well so every public permission-request surface exposes the metadata.
export type PermissionRequest = GeneratedPermissionRequest & {
readonly managedApprovalRequired?: boolean;
};
- Files reviewed: 2/2 changed files
- Comments generated: 0 new
- Review effort level: Medium
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c7f00b84-b0a7-4cdf-aca9-ffd49737f26e
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Comments suppressed due to low confidence (1)
nodejs/src/types.ts:1145
- The behavior change leaves the public README inaccurate:
nodejs/README.md:39,:133, and:856-866still describeapproveAllas allowing every request/tool call. With a managed request it now returnsno-result, so following those docs can leave execution pending until the consumer explicitly resolves the permission. Please update the permission-handling docs and examples to describe this exception and how hosts should resolve it.
export const approveAll: PermissionHandler = (request) =>
request.managedApprovalRequired ? { kind: "no-result" } : { kind: "approve-once" };
- Files reviewed: 4/4 changed files
- Comments generated: 0 new
- Review effort level: Medium
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Comments suppressed due to low confidence (1)
nodejs/README.md:869
- The immediately following custom-handler example still returns
approve-oncefor every non-shell request without checkingmanagedApprovalRequired. Copying it therefore auto-approves managed Read, Edit, or Domain asks, contradicting the human-approval requirement documented here. Update that example to route flagged requests through a human confirmation flow (or leave them unanswered).
For requests with `managedApprovalRequired: true`, `approveAll` returns `{ kind: "no-result" }`. The request remains pending and the host must present a human-facing confirmation flow to resolve it explicitly.
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Medium
|
Linked end-to-end validation completed against SDK head Cross-layer audit of the latest runtime session and AHP transcript confirmed:
The assistant's final table overstated downstream tool success for two approved Domain asks (HTTP redirect/404) and mislabeled the |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Files not reviewed (1)
- go/rpc/zsession_events.go: Generated file
Comments suppressed due to low confidence (1)
java/src/main/java/com/github/copilot/rpc/PermissionHandler.java:60
APPROVE_ALLnow returnsno-result, but Java's protocol-v2 dispatch path explicitly rejects that value:RpcHandlerDispatcher.handlePermissionRequestlines 222-237 throws and then sendsDENIED_COULD_NOT_REQUEST_FROM_USER. Consequently a managed request is denied rather than left pending for a human decision. The dispatcher must suppress the response forno-result(as the other SDKs do) before this handler can satisfy the documented contract.
PermissionHandler APPROVE_ALL = (request,
invocation) -> CompletableFuture.completedFuture(Boolean.TRUE.equals(request.getManagedApprovalRequired())
? PermissionRequestResult.noResult()
: PermissionRequestResult.approveOnce());
- Files reviewed: 30/33 changed files
- Comments generated: 0 new
- Review effort level: Medium
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Files not reviewed (1)
- go/rpc/zsession_events.go: Generated file
Comments suppressed due to low confidence (1)
rust/src/session.rs:1526
- This unwraps
permissionRequestbefore constructing the publicPermissionRequestData, changingextrafrom the full notification params to only the nested request. Existing handlers that readextra["permissionRequest"],promptRequest, or other top-level metadata will silently lose those values (the current E2E helper atrust/tests/e2e/permissions.rs:599-622explicitly supports that shape), and it contradictsPermissionRequestData's documented “full params object” contract. Populate the new managed field from the nested value without replacing the existingextrapayload, or explicitly preserve the wrapper for compatibility.
let request_data = event_data
.get("permissionRequest")
.cloned()
.unwrap_or_else(|| event_data.clone());
- Files reviewed: 30/33 changed files
- Comments generated: 1
- Review effort level: Medium
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Files not reviewed (1)
- go/rpc/zsession_events.go: Generated file
Comments suppressed due to low confidence (1)
dotnet/README.md:805
PermissionRequestis the generated base class and does not declareManagedApprovalRequired; only the Shell/Write/Read/Url subclasses do (Generated/SessionEvents.cs:6928-7130). This custom-handler example therefore does not compile as written. Pattern-match the supported variants (asPermissionHandlers.csdoes) before reading the property.
if (request.ManagedApprovalRequired == true)
{
return PermissionDecision.NoResult();
}
- Files reviewed: 25/26 changed files
- Comments generated: 0 new
- Review effort level: Medium
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Files not reviewed (1)
- go/rpc/zsession_events.go: Generated file
Comments suppressed due to low confidence (3)
python/README.md:836
- This async example has the same union issue: several valid permission variants do not define
managed_approval_required, so it raises before reaching the asynchronous approval logic. Guard the optional per-variant attribute as the built-in handler does.
if request.managed_approval_required is True:
python/README.md:811
- The generated
PermissionRequestunion still includes MCP, custom-tool, memory, hook, and extension variants without this attribute. This unconditional access raisesAttributeErrorwhen the handler receives one of those ordinary requests, so the documented handler fails instead of applying its kind-specific decision; use the samegetattrguard asPermissionHandler.approve_all.
This issue also appears on line 836 of the same file.
if request.managed_approval_required is True:
nodejs/README.md:881
PermissionRequestincludes variants such as MCP and custom-tool that do not declaremanagedApprovalRequired, so this direct property access does not type-check for the generated discriminated union. The built-in implementation already uses aninguard; the public example needs the same narrowing or consumers cannot compile it.
if (request.managedApprovalRequired === true) {
- Files reviewed: 25/26 changed files
- Comments generated: 0 new
- Review effort level: Medium
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Why
Enterprise-managed permission
askrules must be answered by a person. SDK hosts need to distinguish those requests from ordinary permission prompts that client settings may auto-approve.This is the public SDK contract for:
The initial runtime scope supports managed Shell, Read, Edit, and Domain selectors. Tool and MCP selectors are deferred.
What
Exposes optional managed-approval metadata on public permission request and
permission.requestedevent paths in every SDK:managedApprovalRequiredmanaged_approval_requiredManagedApprovalRequiredandRequiresManagedApproval()ManagedApprovalRequiredmanaged_approval_requiredgetManagedApprovalRequired()andPermissionRequest.fromJsonValue(...)for generated event valuesBuilt-in approve-all handlers now approve ordinary requests but return
no-resultfor managed requests, leaving them pending for an explicit human-facing host decision. Custom-handler documentation checks the managed flag before kind-specific auto-approval.Python, Go, and Rust codegen augment the pinned CLI schema until the runtime schema update ships in the repository's published CLI dependency. Regeneration is deterministic and the committed generated diff contains only the managed approval field.
Validation
go test ./...,golangci-lint run ./..., and Go docs validation-D warnings, nightly rustfmt, and reproducible codegen; the full replay E2E run had two unrelated snapshot mismatchesmvn verify, focused permission/dispatcher tests, Spotless, Checkstyle, and Java docs validation